package com.zhang.controller;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.zhang.common.dto.PasswordDto;
import com.zhang.common.lang.Const;
import com.zhang.common.lang.Result;
import com.zhang.entity.SysUser;
import com.zhang.entity.SysUserRole;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.security.Principal;
import java.time.LocalDateTime;
import java.util.*;


@RestController
@RequestMapping("/sys/user")
public class SysUserController extends BaseController{
    @Autowired
    BCryptPasswordEncoder bCryptPasswordEncoder;    //SpringSecurity的密码加密方式
    @Autowired
    Environment environment;    //SpringBoot内置，用于获取配置文件中项目相关的属性

    //获取所有用户列表
    @GetMapping("/list")
    @PreAuthorize("hasAuthority('sys:user:list')")
    Result getUserList(@RequestParam(value = "name",required = false) String name){
        IPage<SysUser> pageUsers = sysUserService.page(getPage(),        //获取分页封装类，方法在父类BaseController中
                new QueryWrapper<SysUser>().like(StrUtil.isNotBlank(name), "username", name));//name不为空才加入此条件(通过搜索功能获取列表)
        pageUsers.getRecords().forEach(user->sysUserService.getUserRoles(user));
        return Result.succ(pageUsers);
    }

    //获取单个用户信息
    @GetMapping("/info/{id}")
    @PreAuthorize("hasAuthority('sys:user:list')")
    Result getUserInfo(@PathVariable("id") Long id){
        SysUser user = sysUserService.getById(id);
        Assert.notNull(user,"找不到该用户");  //user为空会报异常
        sysUserService.getUserRoles(user);
        return Result.succ(user);
    }

    //保存新增的用户
    @PostMapping("/save")
    @PreAuthorize("hasAuthority('sys:user:save')")
    Result saveUserInfo(@RequestBody @Validated SysUser user){   //加了@Validated注解，validation工具包会进行数据校验
        user.setCreated(LocalDateTime.now());
        user.setPassword(bCryptPasswordEncoder.encode(Const.Default_Password)); //初始密码加密后保存
        user.setAvatar(Const.Default_Avatar);   //默认头像
        sysUserService.save(user);
        return Result.succ(user);
    }

    //更新修改的用户
    @PostMapping("/update")
    @PreAuthorize("hasAuthority('sys:user:update')")
    Result updateUserInfo(@RequestBody @Validated SysUser user){
        user.setUpdated(LocalDateTime.now());
        sysUserService.updateById(user);
        return Result.succ(user);
    }

    //删除用户，可批量删除
    @PostMapping("/delete")
    @PreAuthorize("hasAuthority('sys:user:delete')")
    @Transactional  //使用数据库的事务机制，数据要么全部操作成功，要么全不成功
    Result deleteUsers(@RequestBody Long[] ids){
        sysUserService.removeByIds(Arrays.asList(ids));
        sysUserRoleService.remove(new QueryWrapper<SysUserRole>().in("user_id",ids));
        return Result.succ(ids);
    }

    //给用户分配角色
    @PostMapping("/role/{userId}")
    @PreAuthorize("hasAuthority('sys:user:role')")
    @Transactional  //使用数据库的事务机制，数据要么全部操作成功，要么全不成功
    Result giveUserRoles(@PathVariable("userId") Long userId,@RequestBody Long[] roleIds){
        List<SysUserRole> sysUserRoles = new ArrayList<>();
        Arrays.stream(roleIds).forEach(roleId->sysUserRoles.add(new SysUserRole(userId,roleId)));
        sysUserRoleService.remove(new QueryWrapper<SysUserRole>().eq("user_id",userId));    //先删除之前的记录
        sysUserRoleService.saveBatch(sysUserRoles);
        //★★用户角色变化时一定要清除用户权限缓存以便更新权限
        sysUserService.clearUserAuthorityInfo(sysUserService.getById(userId).getUsername());
        return Result.succ("操作成功");
    }

    //重置用户密码为默认密码
    @PostMapping("/repass")
    @PreAuthorize("hasAuthority('sys:user:repass')")
    Result resetPassword(@RequestBody Long id){
        SysUser user = sysUserService.getById(id);
        user.setPassword(bCryptPasswordEncoder.encode(Const.Default_Password));
        user.setUpdated(LocalDateTime.now());
        sysUserService.updateById(user);
        return Result.succ("修改成功");
    }

    //更改用户密码
    @PostMapping("/updatePass")
    Result updatePassword(@RequestBody PasswordDto passwordDto, Principal principal){
        SysUser user = sysUserService.getByUsername(principal.getName());
        boolean matches = bCryptPasswordEncoder.matches(passwordDto.getOldPassword(), user.getPassword());//对比密码
        if(!matches){
            return Result.fail("旧密码不正确");
        }
        user.setPassword(bCryptPasswordEncoder.encode(passwordDto.getNewPassword()));
        user.setUpdated(LocalDateTime.now());
        sysUserService.updateById(user);
        return Result.succ("修改成功");
    }

    //更新用户头像
    @PostMapping("/avatar")
    public Result updateAvatar(@RequestParam("file")MultipartFile multipartFile,Principal principal) throws IOException {
        String fileName = multipartFile.getOriginalFilename();
        String[] splits = fileName.split("\\.");  //用于获取文件后缀
        String avatarName = principal.getName()+"."+splits[splits.length-1];
        String avatarPath = Const.Default_Avatar_FilePath+"/"+avatarName;

        File file = new File(Const.Default_Avatar_FilePath);
        if(!file.exists()){     //目录不存在则创建目录
            file.mkdirs();
        }

        //头像存储到对应路径
        File upFile = new File(avatarPath);
        if(upFile.exists()){
            upFile.delete();    //删除此用户之前的头像
        }
        multipartFile.transferTo(upFile);   //保存新头像

        //更新数据库中的头像路径
        SysUser user = sysUserService.getOne(new QueryWrapper<SysUser>().eq("username", principal.getName()));
        user.setAvatar(Const.Base_Url+"/sys/user/getAvatar/"+avatarName);

        sysUserService.updateById(user);

        return Result.succ("");
    }

    //获取头像文件
    @GetMapping("/getAvatar/{path}")
    public void getAvatar(@PathVariable("path") String path ,HttpServletResponse response) throws IOException{
        File file = new File(Const.Default_Avatar_FilePath+"/"+path);
        FileInputStream fileInputStream = new FileInputStream(file);
        ServletOutputStream servletOutputStream = response.getOutputStream();
        byte[] bytes = new byte[1024];
        while (fileInputStream.read(bytes)!=-1){
            servletOutputStream.write(bytes);
            servletOutputStream.flush();
        }
        fileInputStream.close();
        servletOutputStream.close();
        return;
    }
}

